package com.isoftstone.industry.aaa.core.service.accounting.charging.impl;

import java.sql.Timestamp;
import java.util.Date;

import org.springframework.stereotype.Service;

import com.isoftstone.industry.persistance.bean.BillingList;
import com.isoftstone.industry.persistance.bean.ChargingItem;
import com.isoftstone.industry.persistance.bean.PricingInfo;
import com.isoftstone.industry.persistance.bean.PricingInfoSnapshot;
import com.isoftstone.industry.persistance.bean.ProductInstance;
import com.isoftstone.industry.persistance.bean.TariffSnapshot;
import com.isoftstone.industry.persistance.bean.Unit;
import com.isoftstone.industry.aaa.constants.Constants;
import com.isoftstone.industry.aaa.core.log.ILogMessages;
import com.isoftstone.industry.aaa.core.service.accounting.charging.IChargingEngine;
import com.isoftstone.modules.core.utils.DateUtils;

@Service("periodicChargingEngine")
public class PeriodicChargingEngine extends AbstractChargingEnginer implements IChargingEngine
{
	@Override
	public void charge4Postpaid()
	{
		PricingInfoSnapshot pricingInfoSnap = chargingItemDetail.getPricingInfoSnapshot();
		ChargingItem chargingItem = chargingItemDetail.getChargingItem();
		ProductInstance prodInst = chargingItem.getProdInst();
		String calcMethod = pricingInfoSnap.getCalcMethod();
		// 周期性计费只支持直接计算
		if (PricingInfo.ICalcMethod.DIRECT.equals(calcMethod))
		{
			TariffSnapshot tariffSnap = pricingInfoSnap.getTariffList().get(0);
			Unit timingUnit = tariffSnap.getTimingUnit(); // 间隔时间单位
			int timingRate = tariffSnap.getTimingRate().intValue(); // 间隔时间周期
			String timingCode = timingUnit.getCode();
			Date effDate = chargingItem.getEffDate();
			Date expDate = chargingItem.getExpDate();
			// 取上一次计费的计费周期截止日期
			Date lastChargingEndDate = chargingItemDetail.getChargingEndDate();
			// 计费开始日期
			Timestamp start = null;
			if (lastChargingEndDate == null)
			{
				start = DateUtils.createStartTime(effDate);
			} else
			{
				start = DateUtils.createStartTime(DateUtils.adjustByDay(lastChargingEndDate, 1));
			}
			// 当前计费周期截止日期
			Date chargingEndDate = billingCycle.getEndDate();
			// 帐目金额
			Double amount = 0.00;
			// 计费子项明细需要更新的上次计费时间
			Timestamp modifiedChargingTime = DateUtils.getCurrentTimestamp();
			// 周期性计费只支持年、月、日
			// 年
			if (Unit.TimeUnit.YEAR.equals(timingCode))
			{
				// 如果到了计费周期，则计算该周期的费用
				amount = tariffSnap.getFixedPrice();
				// 更新计费周期截止日
				lastChargingEndDate = DateUtils.addYear(start, timingRate);
				logger.info(ILogMessages.CHARGING_PERIODIC4USER, user.getUsername(), prodInst.getSn(), billingCycle.getName(), pricingInfoSnap
						.getName(), tariffSnap.getFixedPrice() + "元/" + timingRate + "年", timingRate + "年", amount);
				// 月
			} else if (Unit.TimeUnit.MONTH.equals(timingCode))
			{
				String monthChargingMode = systemProperties.getMonthChargingMode();
				Date periodStart = null;
				if (lastChargingEndDate == null)
				{
					// 如果第一次计费，则取生效日期的月初
					periodStart = DateUtils.getFirstDayOfMonth(effDate);
				} else
				{
					// 计费周期开始日期，为上次计费截止日期+1天
					periodStart = DateUtils.adjustByDay(lastChargingEndDate, 1);
				}
				// 计费周期结束日期为帐务周期结束日期
				Date periodEnd = billingCycle.getEndDate();

				// 如果计费周期在有效期内，费用=当前周期价格
				if (DateUtils.isDateBeforeOrEqual(effDate, periodStart) && DateUtils.isDateBeforeOrEqual(periodEnd, expDate))
				{
					amount = tariffSnap.getFixedPrice();
					lastChargingEndDate = periodEnd;
					// 如果计费周期开始日期先于有效期
				} else if (periodStart.before(effDate) && DateUtils.isDateBeforeOrEqual(periodEnd, expDate))
				{
					// 如果按整月计算
					if (Constants.MONTH_CHARGING_MODE_FULL_MONTH.equals(monthChargingMode))
					{
						amount = tariffSnap.getFixedPrice();
						// 按实际天数计算
					} else if (Constants.MONTH_CHARGING_MODE_EACH_DAY.equals(monthChargingMode))
					{
						// 费用=一个周期月数减一个月的费用+一个月中有效天数的费用
						amount = (tariffSnap.getFixedPrice() / timingRate * (timingRate - 1));
						amount += (tariffSnap.getFixedPrice() / timingRate / DateUtils.getDaysInMonth(effDate) * DateUtils
								.getLeftDaysInMonth(effDate));
						// 15号前一个月，15号后半个月
					} else if (Constants.MONTH_CHARING_MODE_HALF_MONTH.equals(monthChargingMode))
					{
						amount = tariffSnap.getFixedPrice() / timingRate * (timingRate - 1);
						if (DateUtils.getDayOfMonth(effDate) < 15)
						{
							amount += tariffSnap.getFixedPrice();
						} else
						{
							amount += (tariffSnap.getFixedPrice() / 2);
						}
					}
					lastChargingEndDate = periodEnd;
					// 有效期在计费周期之内，费用=价格/定价周期间隔*使用周期时长
				} else if (periodStart.before(effDate) && periodEnd.after(expDate))
				{
					int usageInterval = DateUtils.getIntervalMonths(effDate, expDate);
					amount = tariffSnap.getFixedPrice() / timingRate * usageInterval;
					lastChargingEndDate = expDate;
					// 生效日期先于计费周期起始日期，失效日期先于计费周期截止日期
				} else if (periodStart.after(effDate) && expDate.before(periodEnd))
				{
					// 获取该周期使用了多少个月
					int usageInterval = DateUtils.getIntervalMonths(periodStart, expDate);
					amount = tariffSnap.getFixedPrice() / timingRate * usageInterval;
					// 如果按照整月计算，则在第一个周期计算过了，结束的这个周期就不需要计算费用了
					if (Constants.MONTH_CHARGING_MODE_FULL_MONTH.equals(monthChargingMode))
					{
						// 忽略，不需要计算
						// 按实际天数计算
					} else if (Constants.MONTH_CHARGING_MODE_EACH_DAY.equals(monthChargingMode))
					{
						// 费用=整体月数的费用+一个月中有效天数的费用
						amount = (tariffSnap.getFixedPrice() / timingRate * (timingRate - 1));
						double famount = (tariffSnap.getFixedPrice() / timingRate / DateUtils.getDaysInMonth(effDate) * DateUtils
								.getLeftDaysInMonth(effDate));
						// 为了解决开始日期哪个月的天数与结束日期月的天数不一样，导致的计算数额不一样，现在改为最后一个结束日期哪个周期的钱的算法改为：
						// 每个月的定价金额-开始日期那一月的已扣金额
						amount = amount + (tariffSnap.getFixedPrice() / timingRate - famount);
						// 15号前一个月，15号后半个月
					} else if (Constants.MONTH_CHARING_MODE_HALF_MONTH.equals(monthChargingMode))
					{
						// 如果失效日期在15号之前，表示在生效日期那个周期已经按照整月计算了
						if (DateUtils.getDayOfMonth(effDate) < 15)
						{
							// 忽略，不需要计算
						} else
						{
							amount += (tariffSnap.getFixedPrice() / 2);
						}
					}
					lastChargingEndDate = expDate;
				}
				logger.info(ILogMessages.CHARGING_PERIODIC4USER, user.getUsername(), prodInst.getSn(), billingCycle.getName(), pricingInfoSnap
						.getName(), tariffSnap.getFixedPrice() + "元/" + timingRate + "月", timingRate + "月", amount);
				// 日
			} else if (Unit.TimeUnit.DAY.intern() == timingCode.intern())
			{
				if (chargingEndDate.after(expDate))
				{
					chargingEndDate = expDate;
				}
				// 获取当前时间与上一次计费时间之间相隔的天数
				int interval = DateUtils.getIntervalDays(start, chargingEndDate) + 1;
				// 如果还没有达到计费间隔，则不需要进行计费
				if (interval < timingRate)
				{
					logger.info(ILogMessages.CHARGING_RETURN_PERIODIC4USER, user.getUsername(), prodInst.getSn(), billingCycle.getName(),
							pricingInfoSnap.getName(), timingRate + "日", interval + "日");
					return;
				} else
				{
					// 需要计费多少个周期
					int rate = interval / timingRate;
					if (expDate.after(chargingEndDate) || expDate.equals(chargingEndDate))
					{
						amount = tariffSnap.getFixedPrice() * rate;
						lastChargingEndDate = DateUtils.adjustByDay(start, rate * timingRate - 1);
					} else
					{
						amount = tariffSnap.getFixedPrice() / timingRate * interval;
						lastChargingEndDate = expDate;
					}
					logger.info(ILogMessages.CHARGING_PERIODIC4USER, user.getUsername(), prodInst.getSn(), billingCycle.getName(), pricingInfoSnap
							.getName(), tariffSnap.getFixedPrice() + "元/" + timingRate + "日", interval + "日", amount);
				}
			}
			Timestamp end = DateUtils.createEndTime(lastChargingEndDate);
			BillingList billingList = createBillingList(user, chargingItemDetail, prodInst, pricingInfoSnap.getAcctItemType(),
					BillingList.Type.POST_PAID_PERIODIC, amount, null, null, start, end);
			logger.info(ILogMessages.CHARGING_CREATE_BILLING_LIST, user.getUsername(), prodInst.getSn(), billingList.getSn(),
					BillingList.Type.POST_PAID_PERIODIC, pricingInfoSnap.getAcctItemType().getName(), amount);
			// 更新计费子项明细的上次计费时间和计费周期截止日期
			chargingItemDetailService.changeLastChargingTimeAndChargingEndDate(chargingItemDetail.getId(), modifiedChargingTime, lastChargingEndDate);
		} else
		{
			throw new UnsupportedOperationException("非法的计费模式，一次性计费只支持直接计算方法！");
		}
	}

	@Override
	public void charge4Prepaid()
	{
		BillingList billingList = null;
		PricingInfoSnapshot pricingInfoSnap = chargingItemDetail.getPricingInfoSnapshot();
		ChargingItem chargingItem = chargingItemDetail.getChargingItem();
		ProductInstance prodInst = chargingItem.getProdInst();
		String calcMethod = pricingInfoSnap.getCalcMethod();
		// 周期性计费只支持直接计算
		if (PricingInfo.ICalcMethod.DIRECT.equals(calcMethod))
		{
			TariffSnapshot tariffSnap = pricingInfoSnap.getTariffList().get(0);
			Unit timingUnit = tariffSnap.getTimingUnit(); // 间隔时间单位
			int timingRate = tariffSnap.getTimingRate().intValue(); // 间隔时间周期
			String timingCode = timingUnit.getCode();
			Date effDate = chargingItem.getEffDate();
			effDate = DateUtils.string2Date(DateUtils.date2String(effDate), DateUtils.YYYY_MM_DD_PATTERN);
			Date expDate = chargingItem.getExpDate();
			expDate = DateUtils.string2Date(DateUtils.date2String(expDate), DateUtils.YYYY_MM_DD_PATTERN);
			// 取上一次计费的计费周期截止日期
			Date lastChargingEndDate = chargingItemDetail.getChargingEndDate();
			Timestamp start = null;
			if (lastChargingEndDate == null)
			{
				start = DateUtils.createStartTime(effDate);
			} else
			{
				start = DateUtils.createStartTime(DateUtils.adjustByDay(lastChargingEndDate, 1));
			}
			// 帐目金额
			Double amount = 0.00;
			// 计费子项明细需要更新的上次计费时间
			Timestamp modifiedChargingTime = DateUtils.getCurrentTimestamp();
			// 周期性计费只支持年、月、日
			// 年
			if (Unit.TimeUnit.YEAR.equals(timingCode))
			{
				// 计算一个周期的费用
				amount = tariffSnap.getFixedPrice();
				logger.info(ILogMessages.CHARGING_PERIODIC4USER, user.getUsername(), prodInst.getSn(), "-", pricingInfoSnap.getName(), tariffSnap
						.getFixedPrice()
						+ "元/" + timingRate + "年", timingRate + "年", amount);

				// 更新计费周期截止日
				lastChargingEndDate = DateUtils.addYear(start, timingRate);
				// 月
			} else if (Unit.TimeUnit.MONTH.equals(timingCode))
			{
				String monthChargingMode = systemProperties.getMonthChargingMode();
				Date periodStart = null;
				if (lastChargingEndDate == null)
				{
					// 如果第一次计费，则取生效日期的月初
					periodStart = DateUtils.getFirstDayOfMonth(effDate);
				} else
				{
					// 计费周期开始日期，为上次计费截止日期+1天
					periodStart = DateUtils.adjustByDay(lastChargingEndDate, 1);
				}
				periodStart = DateUtils.string2Date(DateUtils.date2String(periodStart), DateUtils.YYYY_MM_DD_PATTERN);
				Date periodEnd = DateUtils.addMonth(periodStart, timingRate);

				// 如果计费周期在有效期内，费用=当前周期价格
				if (DateUtils.isDateBeforeOrEqual(effDate, periodStart) && DateUtils.isDateBeforeOrEqual(periodEnd, expDate))
				{
					amount = tariffSnap.getFixedPrice();
					lastChargingEndDate = periodEnd;
					// 如果计费周期开始日期先于有效期
				} else if (periodStart.before(effDate) && DateUtils.isDateBeforeOrEqual(periodEnd, expDate))
				{
					// 如果按整月计算
					if (Constants.MONTH_CHARGING_MODE_FULL_MONTH.equals(monthChargingMode))
					{
						amount = tariffSnap.getFixedPrice();
						// 按实际天数计算
					} else if (Constants.MONTH_CHARGING_MODE_EACH_DAY.equals(monthChargingMode))
					{
						// 费用=一个周期月数减一个月的费用+一个月中有效天数的费用
						amount = (tariffSnap.getFixedPrice() / timingRate * (timingRate - 1));
						amount += (tariffSnap.getFixedPrice() / timingRate / DateUtils.getDaysInMonth(effDate) * DateUtils
								.getLeftDaysInMonth(effDate));
						// 15号前一个月，15号后半个月
					} else if (Constants.MONTH_CHARING_MODE_HALF_MONTH.equals(monthChargingMode))
					{
						amount = tariffSnap.getFixedPrice() / timingRate * (timingRate - 1);
						if (DateUtils.getDayOfMonth(effDate) < 15)
						{
							amount += tariffSnap.getFixedPrice();
						} else
						{
							amount += (tariffSnap.getFixedPrice() / 2);
						}
					}
					lastChargingEndDate = periodEnd;
					// 有效期在计费周期之内，费用=价格/定价周期间隔*使用周期时长
				} else if (periodStart.before(effDate) && periodEnd.after(expDate))
				{
					int usageInterval = DateUtils.getIntervalMonths(effDate, expDate);
					amount = tariffSnap.getFixedPrice() / timingRate * usageInterval;
					lastChargingEndDate = expDate;
					// 生效日期先于计费周期起始日期，失效日期先于计费周期截止日期
				} else if (periodStart.after(effDate) && expDate.before(periodEnd))
				{
					// 获取该周期使用了多少个月
					int usageInterval = DateUtils.getIntervalMonths(periodStart, expDate);
					amount = tariffSnap.getFixedPrice() / timingRate * usageInterval;
					// 如果按照整月计算，则在第一个周期计算过了，结束的这个周期就不需要计算费用了
					if (Constants.MONTH_CHARGING_MODE_FULL_MONTH.equals(monthChargingMode))
					{
						// 忽略，不需要计算
						// 按实际天数计算
					} else if (Constants.MONTH_CHARGING_MODE_EACH_DAY.equals(monthChargingMode))
					{
						// 费用=整体月数的费用+一个月中有效天数的费用
						amount = (tariffSnap.getFixedPrice() / timingRate * (timingRate - 1));
						double famount = (tariffSnap.getFixedPrice() / timingRate / DateUtils.getDaysInMonth(effDate) * DateUtils
								.getLeftDaysInMonth(effDate));
						// 为了解决开始日期哪个月的天数与结束日期月的天数不一样，导致的计算数额不一样，现在改为最后一个结束日期哪个周期的钱的算法改为：
						// 每个月的定价金额-开始日期那一月的已扣金额
						// amount += (tariffSnap.getFixedPrice() / timingRate /
						// DateUtils.getDaysInMonth(expDate) *
						// DateUtils.getDayOfMonth(effDate));
						amount = amount + (tariffSnap.getFixedPrice() / timingRate - famount);
						// 15号前一个月，15号后半个月
					} else if (Constants.MONTH_CHARING_MODE_HALF_MONTH.equals(monthChargingMode))
					{
						// 如果失效日期在15号之前，表示在生效日期那个周期已经按照整月计算了
						if (DateUtils.getDayOfMonth(effDate) < 15)
						{
							// 忽略，不需要计算
						} else
						{
							amount += (tariffSnap.getFixedPrice() / 2);
						}
					}
					lastChargingEndDate = expDate;
				}
				logger.info(ILogMessages.CHARGING_PERIODIC4USER, user.getUsername(), prodInst.getSn(), "-", pricingInfoSnap.getName(), tariffSnap
						.getFixedPrice()
						+ "元/" + timingRate + "月", timingRate + "月", amount);

				// 日
			} else if (Unit.TimeUnit.DAY.intern().equals(timingCode))
			{
				// 计算一个周期的费用
				amount = tariffSnap.getFixedPrice();
				logger.info(ILogMessages.CHARGING_PERIODIC4USER, user.getUsername(), prodInst.getSn(), "-", pricingInfoSnap.getName(), tariffSnap
						.getFixedPrice()
						+ "元/" + timingRate + "天", timingRate + "天", amount);

				// 更新计费周期截止日
				lastChargingEndDate = DateUtils.adjustByDay(start, timingRate - 1);
			}
			Timestamp end = DateUtils.createEndTime(lastChargingEndDate);
			billingList = createBillingList(user, chargingItemDetail, prodInst, pricingInfoSnap.getAcctItemType(),
					BillingList.Type.PRE_PAID_PERIODIC, amount, null, null, start, end);
			logger.info(ILogMessages.CHARGING_CREATE_BILLING_LIST, user.getUsername(), prodInst.getSn(), billingList.getSn(),
					BillingList.Type.PRE_PAID_PERIODIC, pricingInfoSnap.getAcctItemType().getName(), amount);
			// 更新计费子项明细的上次计费时间和计费周期截止日期
			chargingItemDetailService.changeLastChargingTimeAndChargingEndDate(chargingItemDetail.getId(), modifiedChargingTime, lastChargingEndDate);
		} else
		{
			throw new UnsupportedOperationException("非法的计费模式，一次性计费只支持直接计算方法！");
		}
	}

}
